﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.Core;
using Castle.Windsor;
using Castle.MicroKernel;
using Castle.Windsor.Configuration.Interpreters;

namespace Skyworth.CRM.Common
{
    /// <summary>
    /// a helper about IOC Container
    /// </summary>
    public sealed class IocContainer
    {
        #region private members region

        private static readonly object _synRoot = new Object();
        private static IocContainer _instance;

        private IKernel _kernel;
        private IWindsorContainer windsor;


        #endregion

        #region property members region

        public IKernel Kernel
        {
            get { return _kernel; }
        }

        public static IocContainer Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_synRoot)
                    {
                        if (_instance == null)
                        {
                            _instance = new IocContainer();
                        }
                    }

                }
                return IocContainer._instance;
            }
        }

        #endregion

        /// <summary>
        /// Reset the singleton
        /// </summary>
        static public void Reset()
        {
            _instance = null;
        }


        /// <summary>
        ///  IOC Initialization.
        /// </summary>
        private IocContainer()
        {
            //IOC containers establishment, and through the most dynamic configuration file by adding components.
            Castle.Core.Resource.ConfigResource source = new Castle.Core.Resource.ConfigResource();
            XmlInterpreter interpreter = new XmlInterpreter(source);
            windsor = new WindsorContainer(interpreter);
            _kernel = windsor.Kernel;
        }



        /// <summary>
        /// Returns a component instance by the type of service.
        /// </summary>
        /// <typeparam name="T">the type of service</typeparam>
        /// <returns>T</returns>
        public T Resolve<T>()
        {
            return (T)_kernel[typeof(T)];
        }

        /// <summary>
        /// Returns a component instance by the service name.
        /// </summary>
        /// <param name="service">the servive that needs to resolve</param>
        /// <returns>object</returns>
        public object Resolve(Type service)
        {
            return _kernel[service];
        }

        /// <summary>
        /// Returns a component instance by the type of service
        /// </summary>
        /// <typeparam name="T">the type of service</typeparam>
        /// <param name="key"></param>
        /// <returns>T</returns>
        public T Resolve<T>(string key)
        {
            return (T)_kernel[key];
        }

        /// <summary>
        /// Returns a component instance by the service name
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object Resolve(string key)
        {
            return _kernel[key];
        }

        /// <summary>
        /// Returns a component instance 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public object Resolve(string key, IDictionary arguments)
        {
            return _kernel.Resolve(key, arguments);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public T Resolve<T>(IDictionary arguments)
        {
            return _kernel.Resolve<T>(arguments);
        }


        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public T Resolve<T>(string key, IDictionary arguments)
        {
            return windsor.Resolve<T>(key, arguments);
        }

        /// <summary>
        /// Add a component with lift style
        /// </summary>
        /// <param name="key"></param>
        /// <param name="classType"></param>
        /// <param name="liftstyle"></param>
        public void AddComponentWithLifestyle(string key, Type classType, LifestyleType liftstyle)
        {
            windsor.AddComponentWithLifestyle(key, classType, liftstyle);
        }

        /// <summary>
        /// Add a component with lift style
        /// </summary>
        /// <param name="key"></param>
        /// <param name="classType"></param>
        /// <param name="serviceType"></param>
        /// <param name="liftstyle"></param>
        public void AddComponentWithLifestyle(string key, Type classType, Type serviceType, LifestyleType liftstyle)
        {
            windsor.AddComponentWithLifestyle(key, classType, serviceType, liftstyle);
        }

        /// <summary>
        /// Add a component with lift style
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="liftstyle"></param>
        public void AddComponentWithLifestyle<T>(string key, LifestyleType liftstyle)
        {
            windsor.AddComponentWithLifestyle<T>(key, liftstyle);
        }

        /// <summary>
        /// Add a component
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void AddComponent<T>()
        {
            windsor.AddComponent<T>();
        }

        /// <summary>
        /// Add a component
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        public void AddComponent<T>(string key)
        {
            windsor.AddComponent<T>(key);
        }

        /// <summary>
        /// Add a component
        /// </summary>
        /// <param name="key"></param>
        /// <param name="classType"></param>
        public void AddComponent(string key, Type classType)
        {
            windsor.AddComponent(key, classType);
        }

        /// <summary>
        /// Add a component
        /// </summary>
        /// <param name="key"></param>
        /// <param name="serveiceType"></param>
        /// <param name="classType"></param>
        public void AddComponent(string key, Type serveiceType, Type classType)
        {
            windsor.AddComponent(key, serveiceType, classType);
        }

        /// Release resource that be used by container.
        public void Dispose()
        {
            _kernel.Dispose();
        }
    }
}
